﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Enumerable = System.Linq.Enumerable;

namespace SmallBasicUtils.Tests
{
	public class CompletedRecipe
	{
		public string CompletedFile { get; set; }

		public CompletedRecipe(string completedFile)
		{
			CompletedFile = completedFile;
		}

		private const string PUBLISHED_ID = "'Published ID#";

		public Tuple<string, string[]> CreateRecipe()
		{
			try
			{
				return CreateRecipeWithException();
			}
			catch (Exception ex)
			{
				throw new Exception("Parsing of {0} threw an exception {1}".Formatted(Name, ex.Message), ex);
			}
		}

		private Tuple<string, string[]> CreateRecipeWithException()
		{
			var lines = Enumerable.ToArray<string>(File.ReadLines(CompletedFile));
			return CreateCompletedRecipeWithException(lines);
		}

		public static Tuple<string, string[]> CreateCompletedRecipeWithException(string[] lines)
		{
			HashSet<string> errors = new HashSet<string>();
			var output = new StringBuilder();
			int start = lines[0].StartsWith(PUBLISHED_ID) ? 1 : 0;
			for (int i = start; i < lines.Count(); i++)
			{
				var line = lines[i];
				if (line.Contains("EndIf") || line.Trim().Length == 0)
				{
					continue;
				}
				var codeLine = lines[++i];
				var cleaned = line.Trim();
				var orderIndex = cleaned.IndexOf("--#");
				var cleanLine = cleaned;
				if (orderIndex < 0)
				{
					errors.Add("Missing order number at end of comment [-- 3]");

				}
				else
				{
					cleanLine = cleaned.Substring(1, orderIndex - 1).Trim();
				}
				cleanLine = "'" + CalculateSpaces(codeLine) + cleanLine;
				output.AppendLine(cleanLine);
				output.AppendLine();
			}
			return new Tuple<string, string[]>(output.ToString(), errors.ToArray());
		}

		private static string CalculateSpaces(string cleanLine)
		{
			int spaces = cleanLine.Length - cleanLine.TrimStart().Length;
			spaces = spaces == 0 ? 1 : spaces * 2;
			string padding = "                                                                    ";
			return padding.Substring(0, spaces);
		}

		public override string ToString()
		{
			return String.Format("Name = {0}\r\nBasePath = {1}", Name, BasePath);
		}

		protected string BasePath
		{
			get { return Path.GetDirectoryName(Path.GetDirectoryName(CompletedFile)); }
		}

		public string Name
		{
			get
			{
				var fileName = Path.GetFileName(CompletedFile);
				var index = fileName.IndexOf(".");
				return fileName.Substring(0, index);
			}
		}

		public string RecipeFile
		{
			get { return BasePath + @"\" + Name + ".smallbasic"; }
		}

		public bool OutputRecipe()
		{
			return OutputRecipe(recipe => File.WriteAllText(RecipeFile, recipe));
		}

		public bool OutputRecipe(Action<string> write)
		{
			// create recipe
			var recipe = CreateRecipe();
			bool different = !File.ReadAllText(RecipeFile).Equals(recipe.Item1);
			// check if files differ
			if (different)
			{
				write(recipe.Item1);
			}
			return different;
		}

		public static IEnumerable<CompletedRecipe> GetAll(string basePath)
		{
			var filePaths = Directory.EnumerateFiles(basePath, "*.smallbasic");
			foreach (var file in filePaths)
			{
				yield return new CompletedRecipe(file);
			}
		}
	}
}